package com.chuangke.file.service.impl;

import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.chuangke.common.constant.ElasticIndexConstants;
import com.chuangke.common.constant.Masks;
import com.chuangke.common.exception.ChuangkeException;
import com.chuangke.common.utils.DateUtils;
import com.chuangke.common.utils.SecurityUtils;
import com.chuangke.elasticsearch.model.ElasticQuery;
import com.chuangke.file.model.FileDbank;
import com.chuangke.file.model.FileDocument;
import com.chuangke.file.model.FileType;
import com.chuangke.file.service.FileDbankService;
import com.chuangke.file.service.FileSearchService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FileSearchServiceImpl implements FileSearchService {
	
	private static final Logger logger = LoggerFactory.getLogger(FileSearchServiceImpl.class);

//	@Autowired
//	private ElasticsearchClient elasticsearchClient;
	@Autowired
	private FileDbankService fileDbankService;

	@Override
	public ElasticQuery<FileDocument> search(ElasticQuery<FileDocument> elasticQuery) {
		if(StrUtil.isBlank((String)elasticQuery.getQuery().get("content"))) {
			elasticQuery.setPages(0);
			elasticQuery.setElapsedTime(0);
			elasticQuery.setTotal(0);
			elasticQuery.setResults(null);
			return elasticQuery;
		}
		
		List<Query> shouldList = new ArrayList<>() ;
		List<Query> mustList = new ArrayList<>() ;
		
		@SuppressWarnings("unchecked")
		List<String> dateRange = (List<String>) elasticQuery.getQuery().get("dateRange") ;
		String fileType = (String) elasticQuery.getQuery().get("fileFormat") ;
		String dbankType = (String) elasticQuery.getQuery().get("fileRange") ;
		
		boolean isAdd = addAuthQueryBuilder(dbankType,shouldList,mustList) ;
		if(!isAdd) {
			return elasticQuery ;
		}

        if (!StrUtil.isBlank(fileType) && !Masks.ALL.equals(fileType)) {
            List<FieldValue> suffixList = Arrays.stream(FileType.DOC_MAP.get(fileType)).map(FieldValue::of).collect(Collectors.toList());
            mustList.add(TermsQuery.of(m -> m.field("suffix").terms(n -> n.value(suffixList)))._toQuery());
        }
		
		
		if(CollectionUtils.isNotEmpty(dateRange) && dateRange.size()==2) {
			long from = DateUtils.getDate(dateRange.get(0), "yyyyMMdd").getTime() ;
			long to = DateUtils.add(DateUtils.getDate(dateRange.get(1), "yyyyMMdd"), Calendar.DATE, 1).getTime();
			mustList.add(RangeQuery.of(n ->  n.field("updatedAt").gte(JsonData.of(from)).lte(JsonData.of(to)))._toQuery()) ;
//			mustList.add(QueryBuilders.range(n -> n.date(d -> d.field("updatedAt").gte(String.valueOf(JsonData.of(from)).toString()).lte(String.valueOf(JsonData.of(to)))))) ;

		}
		
		mustList.add(MultiMatchQuery.of(n -> n.fields("title", "content").query((String)elasticQuery.getQuery().get("content")))._toQuery()) ;
		
		
		List<String> fileds = Arrays.asList("id", "title","version", "suffix", "mimeType", "size", "md5hex", "ownerId", "downloadCount",
						"downloadPeopleCount", "remarks", "createdBy", "createdAt", "updatedBy", "updatedAt","dbankId") ;
		
		long start = System.currentTimeMillis();
		SearchResponse<FileDocument> response = null;
//		try {
////			response = elasticsearchClient.search(q -> q.index(ElasticIndexConstants.FILE_INDEX)
////					.query(query -> query
////			                .bool(b -> b.must(mustList).should(shouldList) )
////			        )
////					.highlight(highlightBuilder -> highlightBuilder
////			                .preTags("<font color='red'>")
////			                .postTags("</font>")
////			                .requireFieldMatch(false) //多字段时，需要设置为false
////			                .fields("title", highlightFieldBuilder -> highlightFieldBuilder)
////			                .fields("content", highlightFieldBuilder -> highlightFieldBuilder)
////			        )
////					.from(Integer.parseInt(elasticQuery.getPageNum()-1 + "")).size(Integer.parseInt(elasticQuery.getPageSize() + ""))
////					, FileDocument.class);
//		} catch (ElasticsearchException | IOException e) {
//			throw new ChuangkeException(e) ;
//		}
		 List<Hit<FileDocument>> hits = response.hits().hits();
//		SearchHits<FileDocument> documentHits = 
		long end = System.currentTimeMillis();

		List<FileDocument> results = new ArrayList<>();
		hits.forEach(hit -> {
			FileDocument fileDocument = hit.source();
//			String hitName = StringUtils.join("", hit.getHighlightFields().get("title"));
//			fileDocument.setTitle("".equals(hitName) ? fileDocument.getTitle() : hitName);
//			fileDocument.setContent(StringUtils.join("", hit.getHighlightFields().get("content")));
			results.add(fileDocument);
		});

		elasticQuery.setPages((hits.size() / elasticQuery.getPageSize())
				+ (hits.size() % elasticQuery.getPageSize() == 0 ? 0 : 1));
		elasticQuery.setElapsedTime(end - start);
		elasticQuery.setTotal(hits.size());
		elasticQuery.setResults(results);

		return elasticQuery;
	}
	
	private boolean addAuthQueryBuilder(String dbankType,List<Query> shouldList,List<Query> mustList) {
		String user = SecurityUtils.getUserId() ;
		if(StrUtil.isBlank(user)) {
			logger.error("未获取到当前登录用户");
			return false;
		}
		
		Collection<FileDbank> dbankList = fileDbankService.listAuthDbanks(user, null) ;
		if(CollectionUtils.isEmpty(dbankList)) {
			logger.warn("未找到当前用户{}的权限网盘",user);
			return false;
		}
		
		Query isPublish = MatchQuery.of(m -> m.field("isPublish").query( Masks.BOOL_YES))._toQuery();
		mustList.add(isPublish) ;
		
		Map<String, List<FileDbank>> dbankMap = dbankList.stream().collect(Collectors.groupingBy(FileDbank::getType));
		if(StrUtil.isBlank(dbankType) || (!StrUtil.isBlank(dbankType) && Masks.ALL.equals(dbankType))) {
			for(String dtype : dbankMap.keySet()) {
				List<FieldValue> ids = dbankMap.get(dtype).stream().map(d -> FieldValue.of(d.getId())).collect(Collectors.toList()) ;
				Query query = TermsQuery.of(m -> m.field("dbankBelongType").terms(n -> n.value(Arrays.asList(FieldValue.of(dtype)))).field("dbankId").terms(n -> n.value(ids)))._toQuery() ;
				shouldList.add(query) ;
			}
		}else {
			if(dbankMap.get(dbankType) == null) {
				logger.warn("未找到当前用户{}的权限网盘,网盘类型{}",user,dbankType);
				return false;
			}
			
			List<FieldValue> ids = dbankMap.get(dbankType).stream().map(d -> FieldValue.of(d.getId())).collect(Collectors.toList()) ;
			Query query = TermsQuery.of(m -> m.field("dbankBelongType").terms(n -> n.value(Arrays.asList(FieldValue.of(dbankType)))).field("dbankId").terms(n -> n.value(ids)))._toQuery() ;
			mustList.add(query) ;
		}
		return true ;
	}

}
